﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace NES
{
    public class Emulator
    {
        private M6502 M6502;
        private PPU PPU;
        private Memory Memory;
        private Cartridge Cart;
        private Debugger Debugger;

        public Emulator()
        {
            M6502 = new M6502();
            M6502.Read = ReadMemory;
            M6502.Write = WriteMemory;
            PPU = new NES.PPU();
            Memory = new Memory();
            Cart = new Cartridge();
            Debugger = new Debugger();
        }

        public bool LoadCart(string Path)
        {
            return Cart.LoadCart(Path, Memory.RAM, Memory.VRAM);
        }

        public string GetRAMDump()
        {
            string dump = string.Empty;
            for (int i = 0; i < Commons.RAM_SIZE; i++) dump += string.Format("{0:X4}", i) + ": " + string.Format("{0:X2}", Memory.RAM[i]) + "\n";

            return dump;
        }

        public long[] GetPatternTablesDump()
        {
            // FIXME: pattern tables @ $0000, $1000 de la VRAM
            long[] buffer = new long[256 * 64];
            int tile_counter = 0;
            for (int offset = 0; offset < 0x1000; offset += 16)
            {
                for (int i = 0; i < 8; i++)
                {
                    int palette_index = (((Memory.VRAM[offset | 8] >> (i ^ 7)) & 0x1) << 1) | ((Memory.VRAM[offset] >> (i ^ 7)) & 0x1);
                    buffer[tile_counter++] = Commons.Palette[palette_index];
                }
            }

            return buffer;
        }

        public byte ReadMemory(ushort Address)
        {
            return Memory.Read(Address);
        }

        public void WriteMemory(ushort Address, byte Value)
        {
            Memory.Write(Address, Value);
        }

        public void LaunchEmulation()
        {
            // FIXME: nestest start address
            //M6502.SetPC(0xC000);
            M6502.Reset();

            while (true)
            {
                //M6502 context = M6502.GetContext();
                byte opcode = M6502.Fetch();
                //Debugger.Debug(opcode, context, Memory.RAM);
                M6502.Execute(opcode);
            }
        }
    }
}
